package qeug.shsh.opplugin;

import kd.bos.bill.AbstractBillPlugIn;
import kd.bos.dataentity.entity.DynamicObject;
import kd.bos.dataentity.entity.DynamicObjectCollection;
import kd.bos.entity.AppInfo;
import kd.bos.entity.AppMetadataCache;
import kd.bos.entity.datamodel.IDataModel;
import kd.bos.entity.datamodel.events.AfterAddRowEventArgs;
import kd.bos.entity.datamodel.events.PropertyChangedArgs;
import kd.bos.form.control.Control;
import kd.bos.form.control.Label;
import kd.bos.form.events.BeforeDoOperationEventArgs;
import kd.bos.form.operate.FormOperate;
import kd.bos.orm.query.QCP;
import kd.bos.orm.query.QFilter;
import kd.bos.servicehelper.BusinessDataServiceHelper;
import kd.bos.servicehelper.parameter.SystemParamServiceHelper;
import kd.fi.er.business.tripstd.model.TripStandardDetail;
import kd.sdk.plugin.Plugin;
import kd.fi.er.formplugin.web.tripstandard.util.TripStandardUtils;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.*;

public class TripPersonCohabitPlugin extends AbstractBillPlugIn implements Plugin {

    /* 说明：
     * 主体：二开标准明细和差旅标准金额赋值逻辑；又系统参数-费用核算-多人出差住宿标准控制方式来控制，当为自定义逻辑时，才进行赋值二开逻辑
     * 主要计算逻辑：由同住人定义：同住人为空时清空标准明细，标准金额为未设置；同住人为一人时，赋值所选人的标准；同住人为多人时，最高标准全额加其他人的一半之和。
     * 使用单据：差旅报销单
     * */

    @Override
    public void registerListener(EventObject e) {
        super.registerListener(e);
        Label delexpense = this.getControl("delexpense");//差旅明细删除标签
        delexpense.addClickListener(this);
    }

    @Override
    public void click(EventObject evt) {
        super.click(evt);
        Control source = (Control) evt.getSource();
        String key = source.getKey();
        if ("delexpense".equals(key)) {
            //差旅明细删除标签
            updateAllAccStd();
        }
    }

    @Override
    public void propertyChanged(PropertyChangedArgs e) {
        String propName = e.getProperty().getName();
        if (propName.equals("company")) {
            //申请人公司
            updateAllAccStd();
        } else if (propName.equals("expenseitem") || propName.equals("triparea") || propName.equals("trip2travelers") || propName.equals("qeug_mulbasedatafield") || propName.equals("istravelers")) {
            //差旅项目、出差地域、差旅明细出差人、同住人
            int parentIndex = e.getChangeSet()[0].getParentRowIndex();//行程信息分录下标
            int rowIndex = e.getChangeSet()[0].getRowIndex();//差旅明细分录下标
            updateTripAccStd(parentIndex, rowIndex);
        }
        this.getView().updateView("entryentity");//刷新差旅明细
    }

    @Override
    public void afterBindData(EventObject e) {
        updateAllAccStd();
    }

    @Override
    public void afterAddRow(AfterAddRowEventArgs e) {
        super.afterAddRow(e);
//        String entryProp = String.valueOf(e.getEntryProp());
//        if ("entryentity".equals(entryProp)) {
        //新增差旅明细行数据
//            int parentRowIndex = e.getRowDataEntities()[0].getParentRowIndex();//行程信息分录下标
//            DynamicObjectCollection tripEntryCollection = this.getModel().getDataEntity(true).getDynamicObjectCollection("tripentry");//行程信息分录
//            DynamicObject tripEntry = tripEntryCollection.get(parentRowIndex);//对应行程信息分录
//            DynamicObjectCollection entryEntityCollection = tripEntry.getDynamicObjectCollection("entryentity"); // 差旅明细分录
//            Map<String, Integer> expenseItemCountMap = new HashMap<>(); // 存储差旅项目编号及其出现次数
//            for (int i = 0; i < entryEntityCollection.size(); i++) {
//                DynamicObject entryEntity = entryEntityCollection.get(i);
//                DynamicObject expenseItem = entryEntity.getDynamicObject("expenseitem"); // 差旅项目
//                if (expenseItem != null) {
//                    String number = expenseItem.getString("number");
//                    if ("010".equals(number) || "011".equals(number) || "012".equals(number)) {
//                        this.getModel().deleteEntryRow("entryentity", i + 1);
//                    }
//                }
//            }
//        }
    }

    @Override
    public void beforeDoOperation(BeforeDoOperationEventArgs args) {
        FormOperate operate = (FormOperate) args.getSource();
        String operateKey = operate.getOperateKey();
        if ("submit".equals(operateKey)) {
            updateAllAccStd();
        }
    }

    /**
     * 修改所有行程中的住宿费标准
     */
    private void updateAllAccStd() {
        IDataModel model = this.getModel();
        DynamicObjectCollection tripEntryCollection = model.getEntryEntity("tripentry");//行程信息
        if (tripEntryCollection != null) {
            for (int i = 0; i < tripEntryCollection.size(); i++) {
                DynamicObject tripEntry = tripEntryCollection.get(i);
                DynamicObjectCollection entryEntityCollection = tripEntry.getDynamicObjectCollection("entryentity");//差旅明细
                if (entryEntityCollection != null) {
                    for (int j = 0; j < entryEntityCollection.size(); j++) {
                        DynamicObject entryEntity = entryEntityCollection.get(j);
                        DynamicObject tripExpenseItem = entryEntity.getDynamicObject("expenseitem");//差旅项目
                        if (tripExpenseItem != null && "002".equals(tripExpenseItem.getString("number"))) {
                            //差旅项目为住宿费时进入赋值二开逻辑
                            updateTripAccStd(i, j);
                        }
                    }
                }
            }
        }
    }

    /**
     * 修改指定的行程信息下的子单据体差旅明细中的住宿费标准
     *
     * @param parentEntryIndex 父单据体行程信息的分录下标
     * @param curEntryIndex    子单据体差旅明细的分录下标
     */
    private void updateTripAccStd(int parentEntryIndex, int curEntryIndex) {
        AppInfo appInfo = AppMetadataCache.getAppInfo("em");//获取配置的appId
        String appInfoId = appInfo.getId();
        Object tripPartnerAccStd = SystemParamServiceHelper.getAppParameter(appInfoId, "01", 100000L, "trippartneraccstd");//获取系统参数-费用核算-多人出差住宿标准控制方式
        if (tripPartnerAccStd.equals("cfg")) {
            //当多人出差住宿标准控制方式不为自定义逻辑时，不进行赋值二开逻辑
            IDataModel model = this.getModel();
            DynamicObject tripEntry = model.getEntryRowEntity("tripentry", parentEntryIndex);// 行程信息分录
            if (tripEntry == null) {
                return;
            }
            DynamicObjectCollection entryEntityCollection = tripEntry.getDynamicObjectCollection("entryentity");//费用明细分录
            if (entryEntityCollection != null) {
                DynamicObject entryEntity = entryEntityCollection.get(curEntryIndex);
                DynamicObject tripExpenseItem = entryEntity.getDynamicObject("expenseitem");//差旅项目
                if (tripExpenseItem != null && "002".equals(tripExpenseItem.getString("number"))) {
                    //差旅项目为住宿费时进入赋值二开逻辑
                    Boolean istravelers = (Boolean) this.getModel().getValue("istravelers");//多出差人
                    if (!istravelers) {
                        //非多出差人时
                        return;
                    }
                    StringBuilder standardDetailBuilder = new StringBuilder();//标准明细拼接内容
                    BigDecimal totalStandardAmount = BigDecimal.ZERO;//淡季标准金额合计
                    List<Long> travelerIds = new ArrayList<>();//同住人id集合
                    List<String> travelerNumbers = new ArrayList<>();//同住人编码集合
                    List<String> travelerNames = new ArrayList<>();//同住人名字集合
                    HashMap<Long, Long> cohabitPersonMap = new HashMap<>();//同住人id集合
                    List<BigDecimal> standardAmounts = new ArrayList<>();//住宿费标准金额集合
                    DynamicObject tripArea = entryEntity.getDynamicObject("triparea");// 出差地域
                    if (tripArea == null) return;
                    DynamicObject entryCurrency = entryEntity.getDynamicObject("entrycurrency");// 币种
                    DynamicObjectCollection travelerCollection = entryEntity.getDynamicObjectCollection("qeug_mulbasedatafield");// 同住人
                    if (travelerCollection.size() == 0) {
                        //同住人为空时：清空标准明细，标准金额变为0
                        model.setValue("stddetail", "", curEntryIndex, parentEntryIndex);//标准明细
                        model.setValue("tripstandardamount", BigDecimal.ZERO, curEntryIndex, parentEntryIndex);//差旅标准金额
                        model.setValue("trip2travelers", null, curEntryIndex, parentEntryIndex);//出差人
                    } else if (travelerCollection.size() == 1) {
                        //只有一个人时，只需将对应标准放入标准明细和标准金额中
                        DynamicObject traveler = travelerCollection.get(0).getDynamicObject("fbasedataid");//同住人-单人
                        long travelerId = traveler.getLong("id");
                        travelerIds.add(travelerId);
                        TripStandardDetail tripStdDetail = TripStandardUtils.getAccmodationStdFromPageCache(traveler.getLong("id"), this, entryCurrency.getPkValue(), tripArea.getPkValue(), tripExpenseItem.getPkValue(), null);
                        BigDecimal standardAmount = tripStdDetail == null ? BigDecimal.ZERO : tripStdDetail.getStandardamount();//报销标准金额
                        standardDetailBuilder.append(traveler.getString("name"));
                        buildStandardDetail(standardDetailBuilder, standardAmount, true);//标准明细拼接内容
                        model.setValue("stddetail", standardDetailBuilder.toString(), curEntryIndex, parentEntryIndex);//标准明细
                        model.setValue("tripstandardamount", standardAmount, curEntryIndex, parentEntryIndex);//差旅标准金额
                        Object[] baseDataIds = travelerIds.toArray();
                        model.setValue("trip2travelers", baseDataIds, curEntryIndex, parentEntryIndex);//出出差人
                    } else if (travelerCollection.size() == 2) {
                        //两人同住时，（同级别、不同级别），同级别住宿标准控制，1 * 1.5；不同级别，高标准+低标准的0.5
                        for (int i = 0; i < travelerCollection.size(); i++) {
                            DynamicObject traveler = travelerCollection.get(i).getDynamicObject("fbasedataid");//同住人信息
                            long travelerId = traveler.getLong("id");
                            String travelerNumber = traveler.getString("number");
                            if (cohabitPersonMap.containsKey(travelerId)) continue;// 去重逻辑
                            cohabitPersonMap.put(travelerId, travelerId);
                            travelerIds.add(travelerId);
                            travelerNumbers.add(travelerNumber);
                            String fullName = traveler.getString("name");
                            if (fullName != null && !fullName.isEmpty()) {
                                travelerNames.add(fullName);
                            }
                        }
                        if (!travelerNames.isEmpty()) {
                            String result = String.join(" | ", travelerNames);
                            standardDetailBuilder.append(result);
                        }
                        List<String> reimburseLevels = new ArrayList<>();//报销级别合集
                        HashMap<String, BigDecimal> levelToAmountMap = new HashMap<>();//报销级别加编码集合
                        for (int i = 0; i < travelerNumbers.size(); i++) {
                            String travelerNumber = travelerNumbers.get(i);
                            QFilter[] travelerFilter = new QFilter[]{new QFilter("number", QCP.equals, travelerNumber)};
                            DynamicObject reimburseSetting = BusinessDataServiceHelper.loadSingle("er_reimbursesetting", travelerFilter);//报销级别设置单据
                            if (reimburseSetting != null) {
                                Long travelerId = travelerIds.get(i);
                                TripStandardDetail tripStdDetail = TripStandardUtils.getAccmodationStdFromPageCache(travelerId, this, entryCurrency.getPkValue(), tripArea.getPkValue(), tripExpenseItem.getPkValue(), null);
                                DynamicObject reimburseLevel = reimburseSetting.getDynamicObject("reimburselevel");//报销级别
                                if (reimburseLevel == null || tripStdDetail == null) {
                                    //报销人未设置报销级别或者没有标准时，清空标准明细，标准金额变为0，同住人清空，提示对应报销人未设置报销级别
                                    String reimburseLevelName = reimburseSetting.getString("name");//报销人名称
                                    model.setValue("stddetail", "", curEntryIndex, parentEntryIndex);//标准明细
                                    model.setValue("tripstandardamount", BigDecimal.ZERO, curEntryIndex, parentEntryIndex);//差旅标准金额
                                    model.setValue("qeug_mulbasedatafield", null, curEntryIndex, parentEntryIndex);//同住人
                                    model.setValue("trip2travelers", null, curEntryIndex, parentEntryIndex);//出差人
                                    if (reimburseLevel == null) {
                                        this.getView().showErrorNotification(reimburseLevelName + "未设置报销级别！！");
                                    } else {
                                        this.getView().showErrorNotification(reimburseLevelName + "当前行程标准未设置！！");
                                    }
                                    return;
                                }
                                BigDecimal standardAmount = tripStdDetail.getStandardamount();//报销标准金额
                                standardAmounts.add(standardAmount);
                                String levelCode = reimburseLevel.getString("qeug_textfield");//报销级别编码
                                if (levelCode == null) {
                                    //报销级别编码为空时，默认为Z
                                    levelCode = "Z";
                                }
                                reimburseLevels.add(levelCode);
                                levelToAmountMap.put(levelCode, standardAmount);
                                if (reimburseLevels.size() == 2) {
                                    char level1 = reimburseLevels.get(0).charAt(0);
                                    char level2 = reimburseLevels.get(1).charAt(0);
                                    if (level1 == level2) {
                                        //同级别住宿标准控制，1 * 1.5
                                        BigDecimal maxAmount = Collections.max(standardAmounts);
                                        totalStandardAmount = maxAmount.multiply(new BigDecimal("1.5"));
                                    } else {
                                        //不同级别，高标准+低标准的0.5
                                        if (level1 < level2) {
                                            String higherLevelCode = reimburseLevels.get(0);
                                            BigDecimal higherAmount = levelToAmountMap.get(higherLevelCode);//高标准的金额
                                            totalStandardAmount = higherAmount.add(levelToAmountMap.get(reimburseLevels.get(1)).multiply(new BigDecimal("0.5")));//低标准的一半金额
                                        } else {
                                            String higherLevelCode = reimburseLevels.get(1);
                                            BigDecimal higherAmount = levelToAmountMap.get(higherLevelCode);//高标准的金额
                                            totalStandardAmount = higherAmount.add(levelToAmountMap.get(reimburseLevels.get(0)).multiply(new BigDecimal("0.5")));//低标准的一半金额
                                        }
                                    }
                                }
                            }
                        }
                        buildStandardDetail(standardDetailBuilder, totalStandardAmount, false);//标准明细拼接内容
                        model.setValue("stddetail", standardDetailBuilder.toString(), curEntryIndex, parentEntryIndex);//标准明细
                        model.setValue("tripstandardamount", totalStandardAmount, curEntryIndex, parentEntryIndex);//差旅标准金额
                        Object[] baseDataIds = travelerIds.toArray();
                        model.setValue("trip2travelers", baseDataIds, curEntryIndex, parentEntryIndex);//出差人
                    } else {
                        //同住人超过两人时，清空标准明细，标准金额变为0，同住人清空，并提醒同住人最多为两人
                        model.setValue("stddetail", "", curEntryIndex, parentEntryIndex);//标准明细
                        model.setValue("tripstandardamount", BigDecimal.ZERO, curEntryIndex, parentEntryIndex);//差旅标准金额
                        model.setValue("qeug_mulbasedatafield", null, curEntryIndex, parentEntryIndex);//同住人
                        model.setValue("trip2travelers", null, curEntryIndex, parentEntryIndex);//出差人
                        this.getView().showErrorNotification("同住人最多为两人！！");
                    }
                    BigDecimal entryAmount = (BigDecimal) model.getValue("orientryamount", curEntryIndex, parentEntryIndex);
                    model.setValue("orientryamount", entryAmount.subtract(new BigDecimal(1)), curEntryIndex, parentEntryIndex);
                    model.setValue("orientryamount", entryAmount, curEntryIndex, parentEntryIndex);//为了触发标准金额刷新
                }
            }
        }
    }

    /**
     * 构建标准明细
     *
     * @param detailBuilder  标准明细构建器
     * @param amount         标准金额
     * @param isSinglePerson 是否单人
     */
    private void buildStandardDetail(StringBuilder detailBuilder, BigDecimal amount, boolean isSinglePerson) {
        BigDecimal formattedAmount = amount.setScale(2, RoundingMode.HALF_DOWN);
        if (formattedAmount.equals(new BigDecimal(0).setScale(2, RoundingMode.HALF_DOWN))) {
            detailBuilder.append("未设置");
        } else {
            if (isSinglePerson) {
                detailBuilder.append(":￥").append(formattedAmount).append("/天");
            } else {
                detailBuilder.append("合计:￥").append(formattedAmount).append("/天");
            }
        }
    }
}